﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media.Imaging;
using FFmpeg.AutoGen;
using OpenCvSharp;

namespace FFmpegVideoClip.Lib
{
    internal static class DrawTools
    {
        [System.Runtime.InteropServices.DllImport("gdi32.dll")] 
        private static extern bool DeleteObject(IntPtr hObject);
        

        [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
        public static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count);
        
        [DllImport("msvcrt.dll", EntryPoint = "memmove", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
        public static extern IntPtr memmove(IntPtr dest, IntPtr src, UIntPtr count);


        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", CharSet = CharSet.Ansi)]
        private static extern void MoveMemory(IntPtr Destination, IntPtr Source, int Length);
        
        [DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory", CharSet = CharSet.Ansi)]
        private static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);

        public unsafe static void TimeWriteToWriteableBitmap(this WriteableBitmap writeableBitmap, AVFrame frame, Int32Rect rect, int Stride)
        {
            int size = ffmpeg.av_image_get_buffer_size(AVPixelFormat.AV_PIX_FMT_RGB24, frame.width, frame.height, 1);
            string Text = TimeSpan.FromSeconds(frame.pts * ffmpeg.av_q2d(frame.time_base)).ToString(Tools.TimeSpan_hhmmssfff);
            Mat mat = Mat.FromPixelData(frame.height, frame.width, MatType.CV_8UC3, (nint)frame.data[0]);
            //CopyMemory((nint)frame.data[0], mat.Data, size);
            Cv2.PutText(mat, Text, new OpenCvSharp.Point(2, 10), HersheyFonts.HersheyPlain, 0.5d, Scalar.Black, 2, LineTypes.AntiAlias, false);
            Cv2.PutText(mat, Text, new OpenCvSharp.Point(2, 10), HersheyFonts.HersheyPlain, 0.5d, Scalar.White, 1, LineTypes.AntiAlias, false);
            Application.Current.Dispatcher.Invoke(() => writeableBitmap.WritePixels(rect, mat.Data, size, Stride));
        }


        private static readonly Font drawFont = System.Drawing.SystemFonts.DefaultFont;
        private static readonly StringFormat format = StringFormat.GenericTypographic;
        private static readonly RectangleF RectF = new(2f, 1f, 90f, 25f);
        
        private static GraphicsPath GetStringPath(string s)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddString(s, drawFont.FontFamily, (int)System.Drawing.FontStyle.Bold, 10, RectF, format);
            return path;
        }
        public static void DrawString(this Bitmap bitmap, string Text)
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CompositingMode = CompositingMode.SourceCopy;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                using (GraphicsPath path = GetStringPath(Text))
                {
                    // 阴影代码
                    //RectangleF off = rect;
                    //off.Offset(5, 5);//阴影偏移
                    //using (GraphicsPath offPath = GetStringPath(s, dpi, off, font, format))
                    //{
                    //    Brush b = new SolidBrush(Color.FromArgb(100, 0, 0, 0));
                    //    g.FillPath(b, offPath);
                    //    b.Dispose();
                    //}
                    g.DrawPath(Pens.Black, path);//绘制轮廓（描边）
                    g.FillPath(Brushes.White, path);//填充轮廓（填充）
                }
                g.Flush(FlushIntention.Sync);
            }
        }
        
        public static Bitmap GetThumbnailImageAndDrawString(Bitmap image, string time, int Width, int Height)
        {
            Bitmap bitmap = new Bitmap(Width, Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CompositingMode = CompositingMode.SourceCopy;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(image, new Rectangle(0, 0, Width, Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
                using (GraphicsPath path = GetStringPath(time))
                {
                    // 阴影代码
                    //RectangleF off = rect;
                    //off.Offset(5, 5);//阴影偏移
                    //using (GraphicsPath offPath = GetStringPath(s, dpi, off, font, format))
                    //{
                    //    Brush b = new SolidBrush(Color.FromArgb(100, 0, 0, 0));
                    //    g.FillPath(b, offPath);
                    //    b.Dispose();
                    //}
                    g.DrawPath(Pens.Black, path);//绘制轮廓（描边）
                    g.FillPath(Brushes.White, path);//填充轮廓（填充）
                }
                g.Flush(FlushIntention.Sync);
            }
            return bitmap;
        }

        public static BitmapSource ToBitmapSource(Bitmap bmp)
        {
            nint hBitmap = bmp.GetHbitmap();
            try
            {
                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, nint.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(hBitmap);
            }
        }

        public static Bitmap GetThumbnailImage(Bitmap image, string time, int Width, int Height)
        {
            Bitmap bitmap = new Bitmap(Width, Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CompositingMode = CompositingMode.SourceCopy;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(image, new Rectangle(0, 0, Width, Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
                g.Flush(FlushIntention.Sync);
            }
            return bitmap;
        }

        public static Bitmap CreateDrawingBitmap(nint Data, int PixelWidth, int PixelHeight, int Stride, PixelFormat pixelFormat, float dpiX, float dpiY)
        {
            try
            {
                int size = ffmpeg.av_image_get_buffer_size(AVPixelFormat.AV_PIX_FMT_RGB24, PixelWidth, PixelHeight, 1);
                Bitmap result = new(PixelWidth, PixelHeight, PixelFormat.Format24bppRgb);
                BitmapData bd = result.LockBits(new(0, 0, PixelWidth, PixelHeight), ImageLockMode.WriteOnly, result.PixelFormat);
                bd.Stride = Stride;
                unsafe
                {
                    Span<byte> buffer = new Span<byte>((byte*)Data, size);
                    Span<byte> buffer2 = new Span<byte>((byte*)bd.Scan0, size);
                    buffer.CopyTo(buffer2);
                    bd.Stride = Stride;
                }
                result.UnlockBits(bd);
                result.SetResolution(dpiX, dpiY);
                return result;
            }
            catch (Exception exc)
            {
                LogManage.WriteExceptionInfo("构造Bitmap错误", exc,true);
                return new Bitmap(PixelWidth, PixelHeight, pixelFormat);
            }
        }

        public static void WriteWriteableBitmap(this WriteableBitmap writeableBitmap, Bitmap bitmap)
        {
            int size = ffmpeg.av_image_get_buffer_size(AVPixelFormat.AV_PIX_FMT_RGB24, bitmap.Width, bitmap.Height, 1);
            BitmapData data = bitmap.LockBits(new(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
            writeableBitmap.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height), data.Scan0, size, bitmap.Width * 3);
            bitmap.UnlockBits(data);
        }

        private static string ImageDebugPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"ImageDebug");
        public static unsafe void SaveRGB2ToJpg(string FileName, AVFrame avframe)
        {
            if(!Directory.Exists(ImageDebugPath))
                Directory.CreateDirectory(ImageDebugPath);
            int size = ffmpeg.av_image_get_buffer_size(AVPixelFormat.AV_PIX_FMT_RGB24, avframe.width, avframe.height, 1);
            try
            {
                WriteableBitmap wtbBmp = new WriteableBitmap(avframe.width, avframe.height, 96, 96, System.Windows.Media.PixelFormats.Rgb24, null);
                wtbBmp.WritePixels(new(0, 0, avframe.width, avframe.height), (nint)avframe.data[0], size, avframe.linesize[0]);
                using (FileStream outStream = new FileStream(Path.Combine(ImageDebugPath, $"{FileName}.jpg"), FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                {
                    JpegBitmapEncoder enc = new JpegBitmapEncoder();
                    enc.Frames.Add(BitmapFrame.Create(wtbBmp));
                    enc.Save(outStream);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
            }
        }
    }
}
